/*------------------------------------------------------------------------
|                            FILE DESCRIPTION                            |
------------------------------------------------------------------------*/
/*------------------------------------------------------------------------
|  - File name     : os_task.c
|  - Author        : zeweni
|  - Update date   : 2021.03.25
|  - Copyright(C)  : 2021-2021 zeweni. All rights reserved.
------------------------------------------------------------------------*/
/*------------------------------------------------------------------------
|                            COPYRIGHT NOTICE                            |
------------------------------------------------------------------------*/
/*
 * Copyright (C) 2021, zeweni (17870070675@163.com)

 * This file is part of Ant Real Time Operating System.

 * Ant Real Time Operating System is free software: you can redistribute 
 * it and/or modify it under the terms of the Apache-2.0 License.

 * Ant Real Time Operating System is distributed in the hope that it will 
 * be useful,but WITHOUT ANY WARRANTY; without even the implied warranty 
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * Apache-2.0 License License for more details.

 * You should have received a copy of the Apache-2.0 License.Ant Real Time
 * Operating System. If not, see <http://www.apache.org/licenses/>.
**/
/*------------------------------------------------------------------------
|                                INCLUDES                                |
------------------------------------------------------------------------*/

#include "os_thread.h"
#include "os_mem.h"
#include "os_cpu.h"
#include "os_core.h"

/*------------------------------------------------------------------------
|                                  DATA                                  |
------------------------------------------------------------------------*/

/**
 * @brief   正在运行的线程节点.
 * @details The thread node that is running.
**/
OS_Thread_t *G_OS_Thread_RunNode;

/**
 * @brief     线程就绪链表队列。
 * @details   Thread ready linked list queue.
**/
struct OS_Thread_List G_OS_Thread_RdyList;

/**
 * @brief     线程休眠链表队列。
 * @details   Thread sleep linked list queue.
**/
struct OS_Thread_List G_OS_Thread_SlpList;

/**
 * @brief     线程阻塞链表队列。
 * @details   The thread blocks the linked list queue.
**/
struct OS_Thread_List G_OS_Thread_BlkList;

/**
 * @brief   空闲线程堆栈。
 * @details Idle thread stack.
**/
OS_Thread_Stk Idle_Stack[OS_IDLE_THREAD_STK_SIZE];
 
 /**
 * @brief   空闲线程的指针句柄。
 * @details The pointer handle of the idle thread.
**/
extern OS_Thread_t OS_Idle_Thread;

/*------------------------------------------------------------------------
|                              API FUNCTIONS                             |
------------------------------------------------------------------------*/

/**
 * @brief   OS异常处理函数。
 * @details OS exception handling function.
 * @param   excCode 异常代号.Exception code.
 * @return  None.
 * @note    OS运行出现差错时，回调这个异常处理函数，用来指示出现的错误。
 *          When there is an error in the OS operation, 
 *          this exception handling function is called back to indicate the error.
**/
extern void OS_Exce_Handle(os_uint8_t excCode);


/**
 * @brief   替换阻塞链表上的元素。
 * @details Replaces an element on the blocking list.
 * @param   index1 要被替换的元素1的数组下标。The array index of the element 1 to be replaced.
 * @param   index2 元素2的数组下标。The index of an array with element 2.
 * @return  None.
**/
void OS_BlkList_Replace(os_uint8_t index1,os_uint8_t index2)
{
    G_OS_Thread_BlkList.Node[index1] = G_OS_Thread_BlkList.Node[index2];
    G_OS_Thread_BlkList.Node[index2] = OS_NULL;
}

/**
 * @brief   替换就绪链表上的元素。
 * @details Replaces an element on the ready list.
 * @param   index1 要被替换的元素1的数组下标。The array index of the element 1 to be replaced.
 * @param   index2 元素2的数组下标。The index of an array with element 2.
 * @return  None.
**/
void OS_RdyList_Replace(os_uint8_t index1,os_uint8_t index2)
{
    G_OS_Thread_RdyList.Node[index1] = G_OS_Thread_RdyList.Node[index2];
    G_OS_Thread_RdyList.Node[index2] = OS_NULL;
}

/**
 * @brief     获取就绪线程队列链表中优先级最高的线程。
 * @details   Get the thread with the highest priority in the ready thread list.
 * @param[in] maxPriLabel 最高优先级的线程标号。The thread label with the highest priority.
 * @return    [OS_Thread_t]  更新成功,返回最高优先级的地址。 Update completed.
 * @return    [OS_NULL] 更新失败或者就绪线程链表为空。
 *            The update failed or the ready thread list is empty.
**/
OS_Thread_t OS_RdyList_Get_MaxPrio(os_uint8_t *maxPriLabel)
{
	os_uint8_t index = 0;
	os_uint8_t maxPrio = 0;
	
	*maxPriLabel = 0;
	
	for (index = 0; index < G_OS_Thread_RdyList.Num; index++)
	{
		if ( ((OS_Thread_t) *G_OS_Thread_RdyList.Node[index])->Prio > maxPrio)
		{
			maxPrio = ((OS_Thread_t) *G_OS_Thread_RdyList.Node[index]) -> Prio;
			*maxPriLabel = index;
		}		
	}
	
	return  G_OS_Thread_RdyList.Node[*maxPriLabel];
}


/**
 * @brief     更新线程链表。
 * @details   Update the thread list.
 * @param     list 链表地址。Linked list address.
 * @return    None.
**/
void OS_Update_List(OS_Thread_t *list)
{
	os_uint8_t index = 0;
	
	switch ((*list)->Status)
	{
		case OS_THREAD_READY:
		{
			(OS_Thread_t *)G_OS_Thread_RdyList.Node[G_OS_Thread_RdyList.Num++] = list;
			return;
		}
		case OS_THREAD_SLEEP:
		{
			for(; index < OS_THREAD_LIST_LEN; index++)
			{
				if(G_OS_Thread_SlpList.Node[index] == OS_NULL)
				{
					(OS_Thread_t *)G_OS_Thread_SlpList.Node[index] = list;
					G_OS_Thread_SlpList.Num++;
					return;
				}
			}
			break;
		}
		case OS_THREAD_BLOCK:
		{
			(OS_Thread_t *)G_OS_Thread_BlkList.Node[G_OS_Thread_BlkList.Num++] = list;
			return;
		}
	}
}


/**
 * @brief     静态创建一个线程。成功则返回线程对象的句柄地址。
 * @details   Create a thread, and return the handle address of the thread object if it succeeds.
 * @param[in] thread     线程指针句柄，不可重复。Thread pointer handle, not repeatable.
 * @param[in] thread_id  线程ID，不可重复。The ID of the thread, cannot be repeated.
 * @param[in] entry      线程入口地址。Thread entry address.
 * @param[in] param      线程入口参数。Thread entry parameters.
 * @param[in] priority   线程优先级。Thread priority
 * @param[in] stkAddr    线程堆栈地址。Thread stack address.
 * @param[in] stkSize    线程堆栈大小。Thread stack size.
 * @param[in] slice      线程运行时间片，单位是tick。Thread running time slice, the unit is tick.
 * @return    [OS_Thread_t]  线程初始化成功,返回线程句柄地址。
 *                           The thread is initialized successfully and the address is returned.
 * @return    [OS_NULL]      线程初始化失败。 The thread initialization failed.
 * @note      静态创建线程的方法，用户需要定义一个线程堆栈和线程控制块指针（可选），
 *            指针主要用来做线程控制，比如挂起和删除。
 *            To create a thread statically, 
 *            the user needs to define a thread stack and thread control block pointer (optional),
 *            The pointer is mainly used for thread control, such as suspend and delete.
**/
OS_Thread_t OS_Thread_Static_Create(OS_Thread_t *pthread,
									os_uint8_t id, 
									void(*entry)(void *param),
									void *param,
									os_uint8_t priority,
									OS_Thread_Stk *stkAddr, 
									os_uint8_t stkSize,
									os_uint16_t slice)
{

	os_uint8_t index = OS_Object_Get_Thread_Num_Info();
	OS_Thread_t thread;

	OS_ENTER_CRITICAL(); /* RTOS enters the critical area of the system. */	

	if (index <= OS_THREAD_MAX_NUM)
	{
        if (index > 0 && priority == 0)
        {
            OS_Exce_Handle(EXC_CODE_CONFLICT_IDE_THREAD_PRI); 
        }

        index = 0;
        while ( index < G_OS_Thread_RdyList.Num)
        {
            if ( ((OS_Thread_t)(*G_OS_Thread_RdyList.Node[index++]))->Prio == priority )
            {
                OS_Exce_Handle(EXC_CODE_SAME_THREAD_PRI);
            }
        }

		thread = OS_Malloc(pthread,sizeof(struct OS_Thread));
		
		if (thread != OS_NULL)
		{

            *pthread = thread;
            
            if (OS_Object_Init((OS_Object_t *)pthread, id, OS_Object_Class_Thread) != OS_OK) 
            {
                OS_Exce_Handle(EXC_CODE_OBJECT_INIT_FAIL);
            }

            thread->Status = OS_THREAD_READY;
            thread->Entry = entry;
            thread->StkAddr = stkAddr;
            thread->StkSize = stkSize;
            thread->Prio = priority;
            thread->TickSlice = slice;
            thread->SliCtr = slice;
            
            /** 堆栈的底部（首地址）保存数据的长度，被填充到堆栈中。
                The bottom of the stack holds the length of the data 
                to be filled in the stack. */
            *(stkAddr++) = 15; /* 15 = 2 (thread entry of function address) + 13 (mcu register data) */

            /** 第二个堆栈字节空间读取任务功能的高8位地址。第三个堆栈字节空间读取任务功能的高8位地址。
                The second address read task function low 8 bits address.
                The third address read task function high 8 bits address. */					
            *stkAddr++ = (os_uint16_t)entry;
            *stkAddr = (os_uint16_t)entry >> 8;
            

            /** 首先清除第4个到第16个堆栈字节，此处的位置保存MCU的寄存器值。 
            The fourth to sixteenth stack positions are cleared first,
            * and the position here is to save MCU registers.	*/
            for (index = 0; index < 11; index++) 
            {
                *(++stkAddr) = 0;	
            }

            *stkAddr++ = (os_uint32_t)param;       /*!< R3 */
            *stkAddr++ = (os_uint32_t)param >> 8;  /*!< R2 */
            *stkAddr   = (os_uint32_t)param >> 16; /*!< R1 */

			(OS_Thread_t *)G_OS_Thread_RdyList.Node[G_OS_Thread_RdyList.Num++] = pthread;
			
			OS_EXIT_CRITICAL();
			if (G_OS_Thread_RunNode != OS_NULL) 
			{
				OS_Thread_Schedule();
			}
			return thread;
		}
		
	}

	OS_EXIT_CRITICAL();
	return OS_NULL;
}


/**
 * @brief     动态创建一个线程。成功则返回线程对象的句柄地址。
 * @details   Create a thread, and return the handle address of the thread object if it succeeds.
 * @param[in] thread     线程指针句柄，不可重复。Thread pointer handle, not repeatable.
 * @param[in] thread_id  线程ID，不可重复。The ID of the thread, cannot be repeated.
 * @param[in] entry      线程入口地址。Thread entry address.
 * @param[in] param      线程入口参数。Thread entry parameters.
 * @param[in] priority   线程优先级。Thread priority
 * @param[in] stkAddr    线程堆栈地址。Thread stack address.
 * @param[in] stkSize    线程堆栈大小。Thread stack size.
 * @param[in] slice      线程运行时间片，单位是tick。Thread running time slice, the unit is tick.
 * @return    [OS_Thread_t]  线程初始化成功,返回线程句柄地址。
 *                           The thread is initialized successfully and the address is returned.
 * @return    [OS_NULL]      线程初始化失败。 The thread initialization failed.
 * @note      动态创建线程的方法，用户需要定义一个线程堆栈指针和线程控制块指针（可选），
 *            指针主要用来做线程控制，比如挂起和删除。
 *            To dynamically create threads, users need to define a thread stack pointer
 *            and thread control block pointer (optional),
 *            The pointer is mainly used for thread control, such as suspend and delete.
**/
OS_Thread_t OS_Thread_Create(OS_Thread_t *pthread,
						    os_uint8_t id, 
						    void(*entry)(void *param),
							void *param,
							os_uint8_t priority,
							OS_Thread_Stk **stkAddr, 
							os_uint8_t stkSize,
							os_uint16_t slice)
{
	*stkAddr = (os_uint8_t *)OS_Malloc(stkAddr,stkSize);
	return OS_Thread_Static_Create(
        pthread, id, entry, param, priority, *stkAddr, stkSize, slice);
}									   
/**
 * @brief     休眠一个线程（只能是自身），被休眠的线程主动让出CPU使用权。
 * @details   When a thread is hibernated, the hibernated thread voluntarily surrenders 
 *            the right to use the CPU.
 * @param[in] ticks 系统节拍数。The number of system beats.
 * @return    [OS_OK]  线程休眠成功。 The thread is sleep successfully.
 * @return    [OS_NOK] 线程休眠失败。 Thread sleep failure.
**/
os_err_t OS_Thread_Sleep(os_uint16_t ticks)
{

	/* RTOS enters the critical area of the system. */	
	OS_ENTER_CRITICAL();

	(*G_OS_Thread_RunNode)->SlpCtr = ticks;
	(*G_OS_Thread_RunNode)->Status = OS_THREAD_SLEEP;

	OS_EXIT_CRITICAL();

	OS_Thread_Schedule();
	return OS_OK;
}


/**
 * @brief     线程让出CPU使用权，并进入就绪态。
 * @details   The thread gives up the right to use the CPU and enters the ready state.
 * @param     None.
 * @return    [OS_OK]  线程让出成功。 Thread yields successfully.
 * @return    [OS_NOK] 线程让出失败。 Thread yield failure.
 * @note      如果被操作线程优先级在就绪队列中最高，将会被再次调度。
 *            If the priority of the operated thread is the highest in the ready queue, 
 *            it will be scheduled again.
**/
os_err_t OS_Thread_Yield(void)
{
	(*G_OS_Thread_RunNode)->Status = OS_THREAD_READY;
	OS_Thread_Schedule();
	return OS_OK;
}

/**
 * @brief     挂起一个线程，可以是自身，也可以是其他线程。
 * @details   Suspend a process. This process can be itself or other threads.
 * @param     thread   要被挂起的线程。Thread to be suspended.
 * @return    [OS_OK]  线程挂起成功。 The thread is suspended successfully.
 * @return    [OS_NOK] 线程挂起失败。 The thread suspend failed.
 * @note      如果挂起自身，那么将会触发一次任务调度。
 *            If you suspend itself, it will trigger a task schedule
**/
os_err_t OS_Thread_Suspend(OS_Thread_t *thread)
{
	os_uint8_t index = 0;
	
	OS_ENTER_CRITICAL();
	
	if (thread == OS_THREAD_SELF) 
    {
        thread = G_OS_Thread_RunNode;
    }

	switch ((*thread)->Status)
	{
		case OS_THREAD_READY:
		{					
			/** 删除链表节点。Delete linked list node. */
			for (index = 0; index < G_OS_Thread_RdyList.Num; index++)
			{
				if (thread == (OS_Thread_t *)G_OS_Thread_RdyList.Node[index])
				{
                    OS_RdyList_Replace(index,--G_OS_Thread_RdyList.Num);
					goto update;
				}
			}
			break;
		}
		case OS_THREAD_SLEEP:
		{
			/** 删除链表节点。Delete linked list node. */
			for (index = 0; index < OS_THREAD_MAX_NUM; index++)
			{
				if (thread == (OS_Thread_t *)G_OS_Thread_SlpList.Node[index])
				{
					G_OS_Thread_SlpList.Node[index] =OS_NULL;
					G_OS_Thread_SlpList.Num--;
					goto update;
                    
				}
			}
			break;
		}
		case OS_THREAD_RUNNING:
		{
			G_OS_Thread_RunNode = OS_NULL;
            goto update;
		}
		default: break;
	}	

	OS_EXIT_CRITICAL();
	return OS_NOK;

	update:
	{
		(*thread)->Status = OS_THREAD_BLOCK;
		OS_Update_List(thread);
		OS_EXIT_CRITICAL();
		if (G_OS_Thread_RunNode == OS_NULL)
		{
			OS_Thread_Schedule();
		}
		return OS_OK;
	}
}


/**
 * @brief     恢复一个线程，不可以是自身，只能是其他线程。
 * @details   Resume a process. This process can be itself or other threads.
 * @param[in] thread   要被恢复线程。Thread to be resumed.
 * @return    [OS_OK]  线程恢复成功。 The thread is resumeed successfully.
 * @return    [OS_NOK] 线程恢复失败。 The thread resume failed.
**/
os_err_t OS_Thread_Resume(OS_Thread_t *thread)
{
	os_uint8_t index = 0;
	
	OS_ENTER_CRITICAL();
	
	if (thread == G_OS_Thread_RunNode) return OS_NOK;

	for (index = 0; index < G_OS_Thread_BlkList.Num; index++)
	{
		/** 如果有任务结束阻塞，就将其加入就绪链表。*/
		if ((OS_Thread_t *)G_OS_Thread_BlkList.Node[index] == thread)
		{
			((OS_Thread_t) *G_OS_Thread_BlkList.Node[index])->Status = OS_THREAD_READY;
			
			OS_Update_List((OS_Thread_t *)G_OS_Thread_BlkList.Node[index]);
            OS_BlkList_Replace(index,--G_OS_Thread_BlkList.Num);
			OS_EXIT_CRITICAL();
			return OS_OK;	
		}
	}

	OS_EXIT_CRITICAL();
	return OS_NOK;
}


/**
 * @brief     删除一个线程，可以是自身，也可以是其他线程。
 * @details   Delete a process. This process can be itself or other threads.
 * @param[in] thread 线程指针句柄。
 * @return    [OS_OK]  线程删除成功。 The thread is deleted successfully.
 * @return    [OS_NOK] 线程删除失败。 The thread delete failed.
 * @note      如果删除自身，那么将会触发一次任务调度。
 *            If you delete itself, it will trigger a task schedule
**/
os_err_t OS_Thread_Static_Delete(OS_Thread_t *thread)
{
	os_uint8_t index = 0;
	
	if ( (*G_OS_Thread_RunNode) -> Entry == OS_Idle_Thread) 
	{
		OS_Exce_Handle(EXC_CODE_ILL_CALL_API);
	}
	
	OS_ENTER_CRITICAL();

	if (thread == OS_THREAD_SELF) 
	{
        thread = G_OS_Thread_RunNode;
	}
	
	switch ( (*thread)->Status )
	{
		case OS_THREAD_READY:
		{
			/** 删除链表节点。Delete linked list node. */
			for (index = 0; index < OS_THREAD_MAX_NUM; index++)
			{
				if (thread == (OS_Thread_t *)G_OS_Thread_RdyList.Node[index])
				{
					G_OS_Thread_RdyList.Node[index] =                      \
						G_OS_Thread_RdyList.Node[--G_OS_Thread_RdyList.Num];                             
					G_OS_Thread_RdyList.Node[G_OS_Thread_RdyList.Num] = OS_NULL;
					break;
				}
			}
		}
		case OS_THREAD_SLEEP:
		{
			/** 删除链表节点。Delete linked list node. */
			for (index = 0; index < OS_THREAD_MAX_NUM; index++)
			{
				if (thread == G_OS_Thread_SlpList.Node[index])
				{
					G_OS_Thread_SlpList.Node[index] = OS_NULL;
                    --G_OS_Thread_SlpList.Num;
					break;
				}
			}
			break;
		}
		case OS_THREAD_BLOCK:
		{
			/** 删除链表节点。Delete linked list node. */
			for (index = 0; index < OS_THREAD_MAX_NUM; index++)
			{
				if (thread == G_OS_Thread_BlkList.Node[index])
				{
					OS_BlkList_Replace(index,--G_OS_Thread_BlkList.Num);
					break;
				}
			}
			break;
		}
		case OS_THREAD_RUNNING:
		{
			G_OS_Thread_RunNode = OS_NULL;
            break;
		}
		default: break;
	}
	
    OS_Mem_Send_Recycle_Addr(thread);
	OS_EXIT_CRITICAL();
	if(G_OS_Thread_RunNode == OS_NULL)
	{
	    OS_Thread_Schedule();
	}
	return OS_OK;
}


/**
 * @brief     删除一个线程，可以是自身，也可以是其他线程。
 * @details   Delete a process. This process can be itself or other threads.
 * @param[in] thread  线程指针句柄。
 * @param[in] stkAddr 线程堆栈指针。 
 * @return    [OS_OK]  线程删除成功。 The thread is deleted successfully.
 * @return    [OS_NOK] 线程删除失败。 The thread delete failed.
 * @note      如果删除自身，那么将会触发一次任务调度。
 *            If you delete itself, it will trigger a task schedule
**/
os_err_t OS_Thread_Delete(OS_Thread_t *thread,OS_Thread_Stk **stkAddr)
{
	OS_Mem_Send_Recycle_Addr(stkAddr);
    OS_Thread_Static_Delete(thread);
	return OS_OK;
}

/*------------------------------------------------------------------------
|                    END OF FLIE.  (C) COPYRIGHT zeweni                  |
------------------------------------------------------------------------*/